package com.metaaps.eoraster;


import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeocentricCRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import com.sun.media.imageio.plugins.tiff.TIFFDirectory;
import com.sun.media.imageio.plugins.tiff.TIFFImageReadParam;
import com.sun.media.imageioimpl.plugins.tiff.TIFFImageReader;


/**
 * A class that reads Terrasar-X images including process to extract gcps from the
 * time - slant range xml dataset
 * @author thoorfr, gabbaan
 */
public class TerrasarXImage extends SARImageReader {

    private String[] files;
    private int[] preloadedInterval = new int[]{0, 0};
    private int[] preloadedData;
    private TIFFDirectory td;
    private TIFFImageReader reader;
    private File tfw;
    private AffineTransform matrix;
    private Rectangle bounds;
    private File productxml;
    private Document doc;
    private int MGRows = 0;
    private int MGCols = 0;
    private int MGRefRow = 0;
    private int MGRefCol = 0;
    private double MGRowSpacing = 0;
    private double MGColSpacing = 0;
    private double ImageRowSpacing = 0;
    private double ImageColSpacing = 0;
    private double MGtTime = 0;
    private double MGtauTime = 0;
    private double rangeTimeStart = 0;
    private double rangeTimeStop = 0;
    private double GGtTime = 0;
    private double GGtauTime = 0;
    private double xposition = 0;
    private double yposition = 0;
    private double zposition = 0;
    private int[] stripBounds = {0,0,0};
    //private Namespace ns = Namespace.getNamespace("");
    private Vector<String> bands = new Vector<String>();
    // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
    // #[regen=yes,id=DCE.4A46CCF6-E120-452D-098F-D6C37C7B5C56]
    // </editor-fold>

    public TerrasarXImage() {
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
    // #[regen=yes,id=DCE.9B52B7CE-5899-1EA9-B51A-06AF9276B5FF]
    // </editor-fold>
    @Override
    public int getNBand() {
        return bands.size();
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
    // #[regen=yes,id=DCE.CE6FA7B0-9AE0-5671-FC90-98F878DAE574]
    // </editor-fold>
    @Override
    public List<GCP> getGcps() {
        if (gcps != null) {
            return gcps;
        }
        try {
            gcps = new ArrayList<GCP>();

            //link to the GEOREF.xml file
            File GeoFile = new File((new File((new File(files[0])).getParent())).getParent() + "/ANNOTATION/GEOREF.xml");
            SAXBuilder builder = new SAXBuilder();
            Document geodoc = builder.build(GeoFile);
            Element atts = geodoc.getRootElement().getChild("geolocationGrid");
            //number of Geo Grid elements
            Integer GGRows = new Integer(atts.getChild("numberOfGridPoints").getChild("azimuth").getText());
            Integer GGCols = new Integer(atts.getChild("numberOfGridPoints").getChild("range").getText());
            //Geo Grid point spacing
            double spacingOfGridPointsAz = Double.parseDouble(atts.getChild("spacingOfGridPoints").getChild("azimuth").getText());
            double spacingOfGridPointsRg = Double.parseDouble(atts.getChild("spacingOfGridPoints").getChild("range").getText());
            String GGtTimes = atts.getChild("gridReferenceTime").getChild("tReferenceTimeUTC").getText();
            GGtTimes = GGtTimes.substring(0, GGtTimes.length() - 1);
            GGtTime = Timestamp.valueOf(GGtTimes.replaceAll("T", " ")).getTime();
            GGtauTime = Double.parseDouble(atts.getChild("gridReferenceTime").getChild("tauReferenceTime").getText());

            //read and store the mapping_grid.bin file into an array
            double[][] MappingGrid_t = new double[MGCols][MGRows];
            double[][] MappingGrid_tau = new double[MGCols][MGRows];
            try {
                File MGFile = new File((new File((new File(files[0])).getParent())).getParent() + "/AUXRASTER/MAPPING_GRID.bin");
                InputStream is = new FileInputStream(MGFile);
                DataInputStream dis = new DataInputStream(is);
                long length = MGFile.length();
                if (length > Integer.MAX_VALUE) {
                    throw new IOException("File is too large");
                } else {
                    byte[] bytes = new byte[(int) length];
                    int offset = 0;
                    int numRead = 0;
                    while (offset < bytes.length &&
                            (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                        offset += numRead;
                    }
                    if (offset < bytes.length) {
                        throw new IOException("Could not completely read file " + MGFile.getName());
                    }
                    dis.close();
                    is.close();
                    int az_cnt = 0;
                    int rg_cnt = 0;
                    for (int start = 0; start < offset; start = start + 4) {
                        MappingGrid_t[rg_cnt][az_cnt] = arr2float(bytes, start) * 1000 + MGtTime;
                        start = start + 4;
                        MappingGrid_tau[rg_cnt][az_cnt] = arr2float(bytes, start) + MGtauTime;
                        rg_cnt++;
                        if (rg_cnt == MGCols) {
                            az_cnt++;
                            rg_cnt = 0;
                        }
                    }
                }
            } catch (Exception e) {
                //e.printStackTrace();
            }

            //read and store the GeoGrid from the GEOREF.xml into an array
            int az_cnt = 0;
            int rg_cnt = 0;
            double GeoGrid_t[][] = new double[GGCols][GGRows];
            double GeoGrid_tau[][] = new double[GGCols][GGRows];
            double GeoGrid_lat[][] = new double[GGCols][GGRows];
            double GeoGrid_lon[][] = new double[GGCols][GGRows];
            double GeoGrid_inc[][] = new double[GGCols][GGRows];

            for (Object o : atts.getChildren("gridPoint")) {
                Element elem = (Element) o;
                GeoGrid_t[rg_cnt][az_cnt] = Double.parseDouble(elem.getChild("t").getText()) * 1000 + GGtTime;
                GeoGrid_tau[rg_cnt][az_cnt] = Double.parseDouble(elem.getChild("tau").getText()) + GGtauTime;
                GeoGrid_lat[rg_cnt][az_cnt] = Double.parseDouble(elem.getChild("lat").getText());
                GeoGrid_lon[rg_cnt][az_cnt] = Double.parseDouble(elem.getChild("lon").getText());
                GeoGrid_inc[rg_cnt][az_cnt] = Double.parseDouble(elem.getChild("inc").getText());
                rg_cnt++;
                if (rg_cnt == GGCols) {
                    az_cnt++;
                    rg_cnt = 0;
                }
            }
            int counter = 0;

            //compute gcps looking for each point in GeoGrid
            for (int b = 0; b < GGRows; b++) {//for each line
                for (int a = 0; a < GGCols; a++) {//for each pixel in the line
                    //search the 4 points which surround the selected point of the GeoGrid
                    double GG_t = GeoGrid_t[a][b];
                    double GG_tau = GeoGrid_tau[a][b];

                    int c = 0;
                    int floor_idxrow = -1;
                    int ceil_idxrow = -1;
                    while (c < MGRows - 1) {
                        //the two different conditions consider the possibility to have both ascending and descending mode
                        if (MappingGrid_t[0][c] <= GG_t && GG_t < MappingGrid_t[0][c + 1]) {
                            floor_idxrow = c;
                            ceil_idxrow = c + 1;
                            break;
                        }
                        if (MappingGrid_t[0][c] >= GG_t && GG_t > MappingGrid_t[0][c + 1]) {
                            floor_idxrow = c + 1;
                            ceil_idxrow = c;
                            break;
                        }
                        c++;
                    }
                    if (GG_t == MappingGrid_t[0][c]) {
                        floor_idxrow = c;
                        ceil_idxrow = c;
                    }

                    int d = 0;
                    int floor_idxcol = -1;
                    int ceil_idxcol = -1;
                    while (d < MGCols - 1) {
                        if (MappingGrid_tau[d][0] <= GG_tau && GG_tau < MappingGrid_tau[d + 1][0]) {
                            floor_idxcol = d;
                            ceil_idxcol = d + 1;
                            break;
                        }
                        if (MappingGrid_tau[d][0] >= GG_tau && GG_tau > MappingGrid_tau[d + 1][0]) {
                            floor_idxcol = d + 1;
                            ceil_idxcol = d;
                            break;
                        }
                        d++;
                    }
                    if (GG_tau == MappingGrid_tau[d][0]) {
                        floor_idxcol = d;
                        ceil_idxcol = d;
                    }

                    //compute line and pixel corresponding to the selected GeoGrid point
                    if (GG_t >= 0 && GG_tau >= 0 && ceil_idxcol != -1 && ceil_idxrow != -1) {

                        int line;
                        if (floor_idxrow == ceil_idxrow) {
                            line = new Double(floor_idxrow * MGRowSpacing / ImageRowSpacing).intValue();
                        } else {
                            double floor_line = (floor_idxrow) * MGRowSpacing / ImageRowSpacing;
                            double ceil_line = (ceil_idxrow) * MGRowSpacing / ImageRowSpacing;
                            if (floor_idxrow > ceil_idxrow) {
                                //linked to ascending/descending mode
                                double temp = floor_line;
                                floor_line = ceil_line;
                                ceil_line = temp;
                            }
                            line = new Double(floor_line + ((ceil_line - floor_line) * (GG_t - MappingGrid_t[0][floor_idxrow]) / (MappingGrid_t[0][ceil_idxrow] - MappingGrid_t[0][floor_idxrow]))).intValue();

                        }

                        int pixel;
                        if (floor_idxcol == ceil_idxcol) {
                            pixel = new Double(floor_idxcol * MGColSpacing / ImageColSpacing).intValue();
                        } else {
                            double floor_pix = (floor_idxcol) * MGColSpacing / ImageColSpacing;
                            double ceil_pix = (ceil_idxcol) * MGColSpacing / ImageColSpacing;
                            if (floor_idxcol > ceil_idxcol) {
                                //linked to ascending/descending mode
                                double temp = floor_pix;
                                floor_pix = ceil_pix;
                                ceil_pix = temp;
                            }
                            pixel = new Double(floor_pix + ((ceil_pix - floor_pix) * (GG_tau - MappingGrid_tau[floor_idxcol][0]) / (MappingGrid_tau[ceil_idxcol][0] - MappingGrid_tau[floor_idxcol][0]))).intValue();
                        }
                        GCP gcp = new GCP();

                        counter++;
                        if (pixel >= 0 && pixel < xSize && line >= 0 && line < ySize) {
                            gcp.setXpix(pixel);
                            gcp.setYpix(new Double(line));
                            gcp.setXgeo(GeoGrid_lon[a][b]);
                            gcp.setYgeo(GeoGrid_lat[a][b]);
                            gcp.setAngle((float)GeoGrid_inc[a][b]);
                            gcps.add(gcp);
                        }
                    }
                }
            }

            return gcps;

        } catch (JDOMException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        } catch (IOException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    public static float arr2float(byte[] arr, int start) {
        int i = 0;
        int len = 4;
        int cnt = 3;
        byte[] tmp = new byte[len];
        for (i = start; i <
                (start + len); i++) {
            tmp[cnt] = arr[i];
            cnt--;
        }
        int accum = 0;
        i = 0;
        for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) {
            accum |= ((long) (tmp[i] & 0xff)) << shiftBy;
            i++;
        }
        return Float.intBitsToFloat(accum);
    }


// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.36280E4D-CE78-E42B-818E-109BBA554A95]
// </editor-fold>
    @Override
    public String getAccessRights() {
        return "r";
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.D0A504CE-05E4-8581-2386-5B1FF17389F5]
// </editor-fold>
    @Override
    public String[] getFilesList() {
        return files;
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.C96C2CB4-F58B-E9CA-5017-A116AD5A64C4]
// </editor-fold>
    @Override
    public boolean initialise() {
        try {
            System.out.println(reader.getNumImages(false));
            xSize = reader.getWidth(0);
            ySize = reader.getHeight(0);
            bounds = new Rectangle(0, 0, xSize, ySize);
            gcps = getGcps();
            if (gcps == null) {
                dispose();
                return false;
            }

            //get satellite altitude
            geotransform = GeoTransformFactory.createFromGcps(gcps, "EPSG:4326");
            double radialdist = Math.pow(xposition * xposition + yposition * yposition + zposition * zposition, 0.5);
            MathTransform convert;
            double[] latlon = getGeoTransform().getGeoFromPixel(0, 0, "EPSG:4326");
            double[] position = new double[3];
            convert = CRS.findMathTransform(DefaultGeographicCRS.WGS84, DefaultGeocentricCRS.CARTESIAN);
            convert.transform(latlon, 0, position, 0, 1);
            double earthradial = Math.pow(position[0] * position[0] + position[1] * position[1] + position[2] * position[2], 0.5);
            setMetadata(SATELLITE_ALTITUDE, String.valueOf(radialdist - earthradial));

            // get incidence angles from gcps
            // !!possible to improve
            float firstIncidenceangle = (float) (this.gcps.get(0).getAngle());
            float lastIncidenceAngle = (float) (this.gcps.get(this.gcps.size() - 1).getAngle());
            setMetadata(INCIDENCE_NEAR, String.valueOf(firstIncidenceangle < lastIncidenceAngle ? firstIncidenceangle : lastIncidenceAngle));
            setMetadata(INCIDENCE_FAR, String.valueOf(firstIncidenceangle > lastIncidenceAngle ? firstIncidenceangle : lastIncidenceAngle));


        } catch (TransformException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FactoryException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            dispose();
            Logger.getLogger(GeotiffImage.class.getName()).log(Level.SEVERE, null, ex);



            return false;
        }
        return true;
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.036FA74B-6D3C-1A54-161C-9A37185035C1]
// </editor-fold>
    @Override
    public void setFile(File imageFile) {
        files = new String[2];
        //image path
        files[0] = imageFile.getAbsolutePath();
        name =
                files[0];
        try {
            Iterator readers = ImageIO.getImageReadersByFormatName("tiff");
            reader = (TIFFImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(imageFile);
            reader.setInput(iis);
            td = TIFFDirectory.createFromMetadata(reader.getImageMetadata(0));
            File parent = imageFile;
            if (!parent.isDirectory()) {
                parent = imageFile.getParentFile();
            }
//one level up

            parent = parent.getParentFile();
            int count = 0; //xml counter
            for (File f : parent.listFiles()) {
                if (f.getName().endsWith(".xml")) {
                    productxml = f;
                    //xml path
                    files[1] = f.getAbsolutePath();
                    count++;

                }


            }
            if (productxml != null) {
                if (count > 1) {
                    throw new IOException("more than one .xml file found");
                }

                parseProductXML(productxml);
            } else {
                throw new IOException("Cannot find product.xml");
            }

        } catch (TransformException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            dispose();
        }

    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
    // #[regen=yes,id=DCE.55E69EE2-2B22-C850-1DD6-4CDD6CB326DC]
    // </editor-fold>
    @Override
    public int[] readTile(int x, int y, int width, int height) {
        Rectangle rect = new Rectangle(x, y, width, height);
        rect = rect.intersection(bounds);
        int[] tile = new int[height * width];
        if (rect.isEmpty()) {
            return tile;
        }

        if (rect.y != preloadedInterval[0] || rect.y + rect.height != preloadedInterval[1]) {
            preloadLineTile(rect.y, rect.height);
        }

        int yOffset = xSize;
        int xinit = rect.x - x;
        int yinit = rect.y - y;
        for (int i = 0; i <
                rect.height; i++) {
            //for (int j = 0; j < rect.width; j++) {
            //    int temp = i * yOffset + j + rect.x;
            //   tile[(i + yinit) * width + j + xinit] = preloadedData[temp];
            System.arraycopy(preloadedData, i * yOffset + rect.x, tile, (i + yinit) * width + xinit, rect.width);
        //}
        }

        return tile;
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.091BEB3C-7DA3-1625-A9FA-3CED510139EC]
// </editor-fold>
    @Override
    public int read(int x, int y) {
        TIFFImageReadParam t=new TIFFImageReadParam();
        t.setSourceRegion(new Rectangle(x, y, 1, 1));
        try {
            return reader.read(0, t).getRGB(x, y);
        } catch (IOException ex) {
            Logger.getLogger(GeotiffImage.class.getName()).log(Level.SEVERE, null, ex);
        }
        return -1;
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.A8D91FF2-4D12-67A3-4D11-AB34FEA457C7]
// </editor-fold>
    @Override
    public String getBandName(
            int band) {
        return "" + band;
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.F95FC6F1-B536-4D94-DDED-07B9C0FA48D9]
// </editor-fold>
    @Override
    public void setBand(int band) {
        this.band = band;
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.A95D94A3-4A56-4C07-ACBE-58BE24845725]
// </editor-fold>
    @Override
    public void preloadLineTile(int y, int length) {
                if (y < 0) {
            return;
        }
        preloadedInterval = new int[]{y, y + length};
        Rectangle rect = new Rectangle(0, y, xSize, length);
        TIFFImageReadParam tirp=new TIFFImageReadParam();
        tirp.setSourceRegion(rect);
        try {
            preloadedData = reader.read(0, tirp).getRaster().getSamples(0, 0, xSize, length, band, (int[]) null);
        } catch (Exception ex) {
            Logger.getLogger(GeotiffImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

// <editor-fold defaultstate="collapsed" desc=" UML Marker ">
// #[regen=yes,id=DCE.EE5E26F6-3694-26D5-5C48-4609D842A12E]
// </editor-fold>
    @Override
    public void dispose() {
        super.dispose();
    }

    private void parseProductXML(File productxml) throws TransformException {
        try {
            SAXBuilder builder = new SAXBuilder();
            doc =builder.build(productxml);
            Element atts = doc.getRootElement().getChild("productInfo");
            setMetadata(SATELLITE, new String("TerraSAR-X"));
            setMetadata(SENSOR, atts.getChild("acquisitionInfo").getChild("sensor").getText());
            setMetadata(POLARISATION, atts.getChild("acquisitionInfo").getChild("polarisationList").getChild("polLayer").getText());
            setMetadata(LOOK_DIRECTION, atts.getChild("acquisitionInfo").getChild("lookDirection").getText());
            setMetadata(LOOK_DIRECTION, atts.getChild("acquisitionInfo").getChild("lookDirection").getText());
            setMetadata(MODE, atts.getChild("acquisitionInfo").getChild("imagingMode").getText());
            bands.add((String) getMetadata(POLARISATION));

            setMetadata(PRODUCT, atts.getChild("productVariantInfo").getChild("productType").getText());
            setMetadata(ORBIT_DIRECTION, atts.getChild("missionInfo").getChild("orbitDirection").getText());
            setMetadata(HEIGHT, atts.getChild("imageDataInfo").getChild("imageRaster").getChild("numberOfRows").getText());
            setMetadata(WIDTH, atts.getChild("imageDataInfo").getChild("imageRaster").getChild("numberOfColumns").getText());
            setMetadata(RANGE_SPACING, atts.getChild("imageDataInfo").getChild("imageRaster").getChild("rowSpacing").getText());
            setMetadata(AZIMUTH_SPACING, atts.getChild("imageDataInfo").getChild("imageRaster").getChild("columnSpacing").getText());

            setMetadata(NUMBER_BYTES, new Integer(atts.getChild("imageDataInfo").getChild("imageDataDepth").getText()) / 8);
            setMetadata(ENL, atts.getChild("imageDataInfo").getChild("imageRaster").getChild("azimuthLooks").getText());
            xSize = new Integer(getMetadata(WIDTH).toString());
            ySize = new Integer(getMetadata(HEIGHT).toString());
            setMetadata(HEADING_ANGLE, atts.getChild("sceneInfo").getChild("headingAngle").getText());
            rangeTimeStart = Double.valueOf(atts.getChild("sceneInfo").getChild("rangeTime").getChild("firstPixel").getText());
            rangeTimeStop = Double.valueOf(atts.getChild("sceneInfo").getChild("rangeTime").getChild("lastPixel").getText());
            String time = atts.getChild("sceneInfo").getChild("start").getChild("timeUTC").getText();
            time = time.substring(0, time.lastIndexOf("."));
            setMetadata(TIMESTAMP_START, Timestamp.valueOf(time.replaceAll("T", " ")));
            time = atts.getChild("sceneInfo").getChild("stop").getChild("timeUTC").getText();
            time = time.substring(0, time.lastIndexOf("."));
            setMetadata(TIMESTAMP_STOP, Timestamp.valueOf(time.replaceAll("T", " ")));
            // calculate satellite speed using state vectors
            atts = doc.getRootElement().getChild("platform").getChild("orbit").getChild("stateVec");
            double xvelocity = Double.valueOf(atts.getChildText("velX"));
            double yvelocity = Double.valueOf(atts.getChildText("velY"));
            double zvelocity = Double.valueOf(atts.getChildText("velZ"));
            double satellite_speed = Math.sqrt(xvelocity * xvelocity + yvelocity * yvelocity + zvelocity * zvelocity);
            setMetadata(SATELLITE_SPEED, String.valueOf(satellite_speed));
            xposition = Double.valueOf(atts.getChildText("posX"));
            yposition = Double.valueOf(atts.getChildText("posY"));
            zposition = Double.valueOf(atts.getChildText("posZ"));

            float radarFrequency = new Float(doc.getRootElement().getChild("instrument").getChild("radarParameters").getChild("centerFrequency").getText());
            setMetadata(RADAR_WAVELENGTH, String.valueOf(299792457.9 / radarFrequency));

            setMetadata(SATELLITE_ORBITINCLINATION, "97.44");
            setMetadata(REVOLUTIONS_PERDAY, String.valueOf(11));


            //metadata used for ScanSAR mode during the Azimuth ambiguity computation
            if (getMetadata(MODE).equals("SC")) {
                //extraction of the 4 PRF codes
                int prf_count = 1;
                for (Object o : doc.getRootElement().getChild("instrument").getChildren("settings")) {
                    Element elem = (Element) o;
                    setMetadata("PRF" + prf_count, elem.getChild("settingRecord").getChild("PRF").getText());
                    prf_count++;
                }
                /*double prf_average = 0;
                for (int prf = 1; prf < prf_count; prf++) {
                    prf_average = prf_average + new Double((String) getMetadata(PRF+ prf));
                }
                prf_average = prf_average / (prf_count-1);
                setMetadata(PRF, String.valueOf(prf_average));*/
                setMetadata(PRF, ""); //to recognise the TSX SC in the azimuth computation

                //the SC mode presents 4 strips which overlap, the idea is to consider one strip till the middle of the overlap area
                int b=1;
                for (Object o : doc.getRootElement().getChild("processing").getChildren("processingParameter")) {
                    if (b==4)continue;
                    Element elem = (Element) o;
                    double start_range_time = new Double(elem.getChild("scanSARBeamOverlap").getChild("rangeTimeStart").getText());
                    double stop_range_time = new Double(elem.getChild("scanSARBeamOverlap").getChild("rangeTimeStop").getText());
                    double aver_range_time = start_range_time+(stop_range_time-start_range_time)/2;

                    int stripBound = new Double(((aver_range_time-rangeTimeStart)*xSize)/(rangeTimeStop-rangeTimeStart)).intValue();
                    setMetadata("STRIPBOUND"+b++, new Integer(stripBound).toString());
                }
            }

            setMetadata(K, doc.getRootElement().getChild("calibration").getChild("calibrationConstant").getChild("calFactor").getText());

            //row and cols of the mapping_grid table used for geolocation
            MGRows = new Integer(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("imageRaster").getChild("numberOfRows").getText());
            MGCols =
                    new Integer(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("imageRaster").getChild("numberOfColumns").getText());
            MGRefRow =
                    new Integer(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("gridReferenceTime").getChild("refRow").getText());
            MGRefCol =
                    new Integer(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("gridReferenceTime").getChild("refCol").getText());
            MGRowSpacing =
                    Double.valueOf(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("imageRaster").getChild("rowSpacing").getText());
            MGColSpacing =
                    Double.valueOf(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("imageRaster").getChild("columnSpacing").getText());
            String MGtTimes = doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("gridReferenceTime").getChild("tReferenceTimeUTC").getText();
            MGtTimes = MGtTimes.substring(0, MGtTimes.length() - 1);
            MGtTime = Timestamp.valueOf(MGtTimes.replaceAll("T", " ")).getTime();
            MGtauTime = Double.valueOf(doc.getRootElement().getChild("productSpecific").getChild("projectedImageInfo").getChild("mappingGridInfo").getChild("gridReferenceTime").getChild("tauReferenceTime").getText());
            ImageRowSpacing =
                    Double.valueOf(doc.getRootElement().getChild("productInfo").getChild("imageDataInfo").getChild("imageRaster").getChild("rowSpacing").getText());
            ImageColSpacing =
                    Double.valueOf(doc.getRootElement().getChild("productInfo").getChild("imageDataInfo").getChild("imageRaster").getChild("columnSpacing").getText());


        } catch (JDOMException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(TerrasarXImage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public int getNumberOfBytes() {
        return (Integer) getMetadata(NUMBER_BYTES);
    }

    @Override
    public int getType(boolean oneBand) {
        int nBand = getNBand();
        if (oneBand | nBand == 1) {
            return BufferedImage.TYPE_USHORT_GRAY;
        } else if (nBand == 2) {
            return BufferedImage.TYPE_BYTE_GRAY;
        } else if (nBand == 3) {
            return BufferedImage.TYPE_INT_RGB;
        } else if (nBand == 4) {
            return BufferedImage.TYPE_INT_ARGB;
        }

        return BufferedImage.TYPE_USHORT_GRAY;
    }

    @Override
    public String getFormat() {
        return getClass().getCanonicalName();
    }

    @Override
    public String getName() {
        return getFilesList()[0];
    }


}

